<?php

namespace app\common\command\task;

use app\common\exception\BusinessException;
use app\common\logic\Question;
use app\common\model\AppConfig;
use app\common\model\ImportQuestionTask;
use PhpOffice\PhpWord\IOFactory;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

/**
 * php think cron aiImportQuestion
 */
class AiImportQuestion
{
    /**
     * invoke
     * @throws
     */
    public function invoke()
    {
        // 获取待处理数据
        $where = [['status', '=', 1]];
        $list = app(ImportQuestionTask::class)->where($where)->limit(3)->select();
        $list = $list ? $list->toArray() : [];

        // 循环处理任务
        foreach ($list as $item) {
            // 提取参数
            $id = $item['id'];
            echo '开始执行任务编号' . $id . PHP_EOL;
            try {
                $this->executeItem($item);
            } catch (\Exception $e) {
                var_dump(111);
                $error = $e->getMessage();
                if (strpos($error, 'Zip object') !== false) {
                    $error = '您的文件格式错误，请检查后重新上传';
                }
                if (strpos($error, 'could not be converted to string') !== false) {
                    $error = '您的文档中包含公式或图片，暂不支持自动上传';
                }
                $this->setFail($id, $error);
            }
            echo '结束执行任务编号' . $id . PHP_EOL;
        }
    }

    /**
     * executeItem
     * @throws DataNotFoundException
     * @throws BusinessException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    private function executeItem($item)
    {
        // 提取参数
        $id = $item['id'];

        // 读取word中的文档内容
        $fileContent = $this->getWordContent($item);

        // 文件内容为空则丢弃
        if (!$fileContent) {
            throw new BusinessException('文件内容为空');
        }

        // 文件内容长度过短
        if (mb_strlen($fileContent) < 10) {
            throw new BusinessException('文件内容字符少于10');
        }

        // 调用ai生成解析
        $moonShotService = null;
        $response = $error = '';
        try {
            // 读取配置
            $config = app(AppConfig::class)->getByIdAndType(1000, 'moonShot');

            // 初始化服务
            $aiClass = 'app\common\service\\' . $config['apiService'];
            $moonShotService = app($aiClass, [], true);
            $moonShotService->setApiHost(($config['apiHost']));
            $moonShotService->setResponseFormat(['type' => 'json_object']);
            $max = 3;
            while ($max--) {
                // 如果配置api睡眠时间则等待
                if ($config['apiSleepTime'] > 0) {
                    sleep($config['apiSleepTime']);
                }
                // 调用ai
                $response = $moonShotService->setApiKey($config['apiKey'])->setRoleRule($config['aiImportTxtQuestionRoleRule'])->chat($fileContent);
                $response = trim($response);
                if ($response) {
                    break;
                }
            }
        } catch (\Exception $e) {
            $error = $moonShotService ? $moonShotService->getResponse() : $e->getMessage();
        }

        // 判断是否处理成功
        if (empty($response)) {
            if (empty($error)) {
                $error = 'AI解析失败，请稍后重试';
            }
            throw new BusinessException($error);
        }

        // 解析JSON
        $responseData = json_decode($response, true);
        if (!$responseData) {
            throw new BusinessException('AI解析失败，请稍后重试');
        }
        if ($responseData['code'] != 200) {
            throw new BusinessException('AI解析失败:' . $responseData['message']);
        }

        // 提取全部题目
        $allQuestion = $responseData['data'] ?? [];
        foreach ($allQuestion as $question) {
            //4.请求自己保存题库
            $questionRequest = [
                'type' => 4,
                'uid' => $item['uid'],
                'extend_id' => $item['paper_id'],
                'course_id' => $item['course_id'],
                'question_type' => $question['questionType'],
                'question_data' => [$question],
                'charge_type' => 0,
            ];
            (new Question())->save($questionRequest);
        }

        // 标记成功
        $this->setSuccess($id);
    }

    private function getWordContent($item)
    {
        // 提取参数
        $file_url = $item['file_path'];

        // 下载文件到本地
        $fileBin = file_get_contents($file_url);
        if (!$fileBin) {
            throw new BusinessException('加载远程文件失败');
        }

        $filePath = app()->getRuntimePath() . 'import_question_template.docx';
        $save = file_put_contents($filePath, $fileBin);
        if (!$save) {
            throw new BusinessException('保存远程文件失败');
        }

        // 检查文件是否可读
        if (!is_readable($filePath)) {
            throw new BusinessException('文件不可读取');
        }

        // 文件地址
        $phpWordRead = IOFactory::createReader('Word2007');
        if (!$phpWordRead->canRead($filePath)) {
            $phpWordRead = IOFactory::createReader('Word2007');
        }
        $phpWord = $phpWordRead->load($filePath);

        // 读取word中的文档内容
        $fileContent = '';
        $sections = $phpWord->getSections();
        foreach ($sections as $section) {
            foreach ($section->getElements() as $element) {
                if ($element instanceof \PhpOffice\PhpWord\Element\Text) {
                    $fileContent .= $element->getText() . PHP_EOL;
                } elseif ($element instanceof \PhpOffice\PhpWord\Element\Table) {
                    foreach ($element->getRows() as $row) {
                        foreach ($row->getCells() as $cell) {
                            foreach ($cell->getElements() as $cellElement) {
                                if ($cellElement instanceof \PhpOffice\PhpWord\Element\Text) {
                                    $fileContent .= $cellElement->getText() . PHP_EOL;
                                }
                            }
                        }
                    }
                }
            }
        }

        var_dump($fileContent);

        // 返回
        return $fileContent;
    }

    /**
     * setFail
     * @param $id
     * @param $error
     * @return void
     * @throws BusinessException
     */
    private function setFail($id, $error)
    {
        $where = ['id' => $id];
        $isUpdate = app(ImportQuestionTask::class)->where($where)->update([
            'status' => 3,
            'error' => $error,
            'update_time' => time()
        ]);
        if (!$isUpdate) {
            throw new BusinessException('更新导入任务失败');
        }
    }

    /**
     * setSuccess
     * @param $id
     * @return void
     * @throws BusinessException
     */
    private function setSuccess($id)
    {
        $where = ['id' => $id];
        $isUpdate = app(ImportQuestionTask::class)->where($where)->update([
            'status' => 2,
            'update_time' => time()
        ]);
        if (!$isUpdate) {
            throw new BusinessException('更新导入任务失败');
        }
    }
}